# define _CRT_SECURE_NO_WARNINGS
#include "buff.h"
#include <conio.h>
#include "stdio.h"
#include <process.h>
#include "iostream"
#include <windows.h>
#include <fstream>
#include <vector>
#include <deque>
#include "string.h"
#include "adb_global.h"
#include "db_header.h"
typedef Page Frame;
using namespace std;


long BMgr::get_num_of_frames()
{
    return _num_of_frames;
}
bool BMgr::init_buffer(long _memorySize, long _pgSize)
{
    /*initializing the variables*/
    _memsize = _memorySize;
    _pagesize = _pgSize;
    _num_of_frames = (_memsize/_pagesize);
   
    /*initializing buffer pool*/
//    buffer_frames = new Page[get_num_of_frames()];

	mybuffer.resize(get_num_of_frames());
    cout<<"\nBuffer Size :"<< (int)mybuffer.size()<<" frames\n";
   
    cout<<"yahan to aaya";
    for(long x = 0;x < (int)mybuffer.size();x++)
    {
        mybuffer[x].data[0] = '\0';
        mybuffer[x]._dirty_bit = 0;
        mybuffer[x]._is_pinned = 0;
        mybuffer[x]._page_num = -1;
        mybuffer[x]._priority = -1;
		pfdirectory[x] = -1;
		//cout<<"\npfdirectory["<<x<<"] :"<<(*pfit).second;
    }
   
    /*initializing free list*/
   
    free_frames.assign(get_num_of_frames(),-1);
    long x;
    cout<<"\nin init buffer :"<<free_frames.size();
	
    for(x = 0;x < (int)free_frames.size();x++)
    {
		//cout<<"in for loop";
        free_frames.at(x) = x;
		
    }
	return true;   
}
int BMgr::createDB(char *_dbName, long _numOf_dbPage,  long _pageSize)
{
    FILE *newdb = fopen(_dbName,"w+");
    long _dbsize = _numOf_dbPage * _pageSize;
    if(!newdb)
    {
        cout<<endl<<"Unable to create the file";
        return NULL;
    }
    long l;
    char ch=' ';
    for(l = 0;l < _dbsize;l++)
    {
        fputc(ch,newdb);
    }
    return 0;
}
int BMgr::incrementDB(char *_dbName, long _numOf_dbPage, long _pageSize)
{
    FILE *newdb = fopen(_dbName,"a+");
    long _dbsize = _numOf_dbPage * _pageSize;
    if(!newdb)
    {
        cout<<endl<<"Unable to create the file";
        return NULL;
    }
    rewind(newdb);
    fseek(newdb,ios::end,0);
    long l;
    char ch = '$';
    for(l = 0;l < _dbsize;l++)
    {
        fputc(ch,newdb);
    }

    //return newdb;
    return 1;
}

long BMgr::Replacement_Policy()
{
    int x;
    deque<long>::iterator it1,it2,it3,it4,it5;
    bool flag1=1,flag2=1,flag3=1,flag4=1,flag5=1;
    for(x = 0;x<(int)used_frames.size(); x++)
    {
        it1++,it2++,it3++,it4++,it5++;
        long frame_number = used_frames.at(x);
        int priority = mybuffer[frame_number]._priority;
        if(priority == 1 && flag1)
        {
            flag1 = 0;
            it1--;
        }
        else if(priority == 2 && flag2)
        {
            flag2 = 0;
            it2--;
        }
        else if(priority == 3 && flag3)
        {
            flag3 = 0;
            it3--;
        }
        else if(priority == 4 && flag4)
        {
            flag4 = 0;
            it4--;
        }
        else if(priority == 5 && flag5)
        {
            flag5 = 0;
            it5--;
        }
    }
    if(*it5 != NULL)
        return (*it5);
    if(*it5 != NULL)
        return (*it5);
    if(*it5 != NULL)
        return (*it5);
    if(*it5 != NULL)
        return (*it5);
    if(*it5 != NULL)
        return (*it5);
    return 0;

}

void BMgr::findFreeFrame(long *_frameNum)
{
    //1. Find if free_frame list is empty or not
    //2. If not empty then return the first frame number from the list
    if(free_frames.size())
    {
		cout<<"\nfree_frames.at(0) :"<<free_frames.at(0);
        *_frameNum = free_frames.at(0);
		free_frames.pop_front();
    }
    //3. If free_frame list empty , i.e. , all frames are in use , call Replacement Policy.
    else
    {
        *_frameNum = Replacement_Policy();
    }
}


Page *BMgr::readPagetoFrame(long _pageNum) //return the page number
{
    // 1. Search in directory for this page (if already present)
    long _frameNum;
	//init_buffer(40960,4096);
    pfit = pfdirectory.find(_pageNum);

	cout<<"pfit :"<<(*pfit).first;
	cout<<"\npfit :"<<(*pfit).second;
	
	cout<<"\n2";
    //if(pfdirectory.find(_pageNum) != NULL)
	if((*pfit).first != NULL)
    {
        //2.If present , then return the frame Number associated with the required page
		return &mybuffer[(*pfit).first];
    }
    else
    {
        //3. If not present , search for any free frame available or find the best contender to be replaced.
        findFreeFrame(&_frameNum);
		pfdirectory[_frameNum] = _pageNum;
    }
	cout<<"\nFrame allocated: "<<_frameNum;
    
    return &mybuffer[_frameNum];
}
Page *BMgr::readPagetoFrame(char *_dbName, long _pageNum) //return the page number
{
    // 1. Search in directory for this page (if already present)
    long _frameNum;
	//init_buffer(40960,4096);
    pfit = pfdirectory.find(_pageNum);
	
	//if(pfdirectory.find(_pageNum) != NULL)
	if((*pfit).first != NULL)
    {
        //2.If present , then return the frame Number associated with the required page
		return &mybuffer[(*pfit).first];
    }
    else
    {
        //3. If not present , search for any free frame available or find the best contender to be replaced.
        findFreeFrame(&_frameNum);
		pfdirectory[_frameNum] = _pageNum;
    }

	cout<<"\n\nFrame allocated: "<<_frameNum;
	cout<<"\npfit FRAME :"<<(*pfit).first;
	cout<<"\npfit PAGE:"<<(*pfit).second;
    
    return &mybuffer[_frameNum];
}

char *readSystable(char *_dbName)
{
    FILE *newdb = fopen(_dbName,"r+");
    char *str = (char *)malloc(sizeof(_sysTable));
    fread(str,1,sizeof(_sysTable),newdb);
    cout<<"ye hai"<<str;
    return str;
}


int BMgr::open_DB(char *_dbName)
{
    //init_buffer(81920,8192);
    cout<<"\nyahan";
    
   
    cout << "0. size: " << (int) mybuffer.size();
  //  mybuffer.at(0).data = readSystable(_dbName);
    mybuffer.at(0)._dirty_bit = 1;
    mybuffer.at(0)._is_pinned = 1;
    mybuffer.at(0)._page_num = 1;    // 1 for systable
    mybuffer.at(0)._priority = 1;  //1 being highest
    used_frames.push_back(0);
   
    pfdirectory[0] = 0;

    cout<<"\nSYSTABLE CONTENTS";
    cout<<endl<<mybuffer.at(0).data;
    cout<<endl<<mybuffer.at(0)._dirty_bit;
    cout<<endl<<mybuffer.at(0)._is_pinned;
    cout<<endl<<mybuffer.at(0)._page_num;
    cout<<endl<<mybuffer.at(0)._priority;


    return 0;
}


void BMgr::showFrame(long framenum)
{
    if (mybuffer[framenum].data  != NULL)
    {
                int j;
                for (int i = 0; i < _pagesize; i += 16)
                {
                        for (j = 0; j < 16; j++)
                                printf("%02x ", mybuffer[framenum].data[i+j]);
                        cout << " ";
                        for (j = 0; j < 16; j++)
    //                            if (isprint(mybuffer[framenum].data[i+j]))
                                     //   cout << mybuffer[framenum].data[i+j];
                        printf("\n");
                }
    }
}

int BMgr::writeFrametoPage(char *_dbName,long _frameNum)
{
    FILE *newdb = fopen(_dbName,"w+");
    if(!newdb)
    {
        cout<<endl<<"Unable to open the file";
        return NULL;
    }
    rewind(newdb);
	cout<<"\nrewind k baad";
    int offset = mybuffer[_frameNum]._page_num * getpagesize();
	cout<<"\noffset :"<<offset;
    fseek(newdb,offset,0);
	int x;
	for(x = 0;x < getpagesize(),*(mybuffer[_frameNum].data+x)!=NULL;x++)
	{
		cout<<"data :"<<(long)*(mybuffer[_frameNum].data+x);
		fputc((int)*(mybuffer[_frameNum].data+x),newdb);
	}
	cout<<"\n writeFrametoPage se return to ho raha hai";
    return 0;
}

int BMgr::commitPage(char *_dbName, long _pageNum)
{
    int success;
    long _frameNum;
    pfit = pfdirectory.find(_pageNum);
    _frameNum = (*pfit).first;
    if (mybuffer[_frameNum]._dirty_bit != 1)
    {
        success = 0;  
    }
    else
    {
        success = writeFrametoPage(_dbName,_frameNum);
    }
	cout<<"\ncommitPage me success ki value ye pahuchi :";success;
	if(used_frames.size() != 0)
	{
		used_frames.erase(used_frames.begin() + _pageNum);
	}
	used_frames.push_back(_pageNum);
    
    cout<<"\n\nPush back kiya gaya hai :"<<_pageNum;
	
    return success;
}




int BMgr::commitFrame(char *_dbName, long _frameNum)
{
    int success;
    if (mybuffer[_frameNum]._dirty_bit != 1)
    {
        success = 0;
    }
    else
    {
        success = writeFrametoPage(_dbName,_frameNum);
    }
    cout<<"\ncommitFrame me success ki value ye pahuchi :"<<success;


	if(used_frames.size() != 0)
	{
		int x;
		for(x = 0;x < (int)used_frames.size();x++)
		{
			if(used_frames.at(x) == _frameNum)
				break;
		}
		used_frames.erase(used_frames.begin() + x);
	}
	used_frames.push_back(_frameNum);
    
	cout<<"\n\nPush back kiya gaya hai :"<<_frameNum;

    return success;
}

int BMgr::commitAll(char *dbName)
{
    int  success;
    long x;
    //1. Calling Commit for each frame in the used_frame list
    for(x = 0; (int)used_frames.size(); x++)
    {
        success = commitFrame(dbName,used_frames.at(x));
    }
    return 0;
}
bool BMgr::close_DB(char *dbName)
{
    //1. Commiting all the frames in the Buffer to the respective pages in the disk.
    commitAll(dbName);

    //2. Freeing all the buffers frames
    delete[] buffer_frames;

    //3. Freeing the Buffer.
    mybuffer.clear();
    mybuffer.reserve(0);
    return 0;
}

void BMgr::setpagesize(int ps)
{
    _pagesize = ps;
}
long BMgr::getmemsize()
{
    return _memsize;
}

long BMgr::getpagesize()
{
    return _pagesize;
}

